package com.vaux.sc2gears.skill;

import hu.belicza.andras.sc2gearspluginapi.Configurable;
import hu.belicza.andras.sc2gearspluginapi.GeneralServices;
import hu.belicza.andras.sc2gearspluginapi.PluginDescriptor;
import hu.belicza.andras.sc2gearspluginapi.PluginServices;
import hu.belicza.andras.sc2gearspluginapi.SettingsControl;
import hu.belicza.andras.sc2gearspluginapi.api.LanguageApi;
import hu.belicza.andras.sc2gearspluginapi.api.ReplayFactoryApi;
import hu.belicza.andras.sc2gearspluginapi.api.SettingsApi;
import hu.belicza.andras.sc2gearspluginapi.api.listener.NewReplayListener;
import hu.belicza.andras.sc2gearspluginapi.api.listener.ProfileListener;
import hu.belicza.andras.sc2gearspluginapi.api.profile.IProfile;
import hu.belicza.andras.sc2gearspluginapi.api.sc2replay.IGameEvents;
import hu.belicza.andras.sc2gearspluginapi.api.sc2replay.IPlayer;
import hu.belicza.andras.sc2gearspluginapi.api.sc2replay.IPlayerSelectionTracker;
import hu.belicza.andras.sc2gearspluginapi.api.sc2replay.IReplay;
import hu.belicza.andras.sc2gearspluginapi.api.sc2replay.ReplayConsts.ActionType;
import hu.belicza.andras.sc2gearspluginapi.api.sc2replay.ReplayConsts.BnetLanguage;
import hu.belicza.andras.sc2gearspluginapi.api.sc2replay.action.IAction;
import hu.belicza.andras.sc2gearspluginapi.api.sc2replay.action.IHotkeyAction;
import hu.belicza.andras.sc2gearspluginapi.api.sc2replay.action.ISelectAction;
import hu.belicza.andras.sc2gearspluginapi.impl.BasePlugin;
import hu.belicza.andras.sc2gearspluginapi.impl.BaseSettingsControl;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.labels.BoxAndWhiskerToolTipGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.renderer.category.BoxAndWhiskerRenderer;
import org.jfree.data.statistics.DefaultBoxAndWhiskerCategoryDataset;
import org.jfree.ui.RefineryUtilities;

/**
 *
 * @author medv4380
 */
public class PlugIn extends BasePlugin implements Configurable {

    Thread runner;
    EnemyProfileListener enemyProfileListener = new EnemyProfileListener();
    ImportArchiveActionListener importArchiveActionListener = new ImportArchiveActionListener();
    File replayFile;
    NewReplayListener nrl = new NRL();
    Controls controls;
    private Set<String> watchedPlayerSet = new HashSet<String>(4);
    private String KEY_WATCHED_PLAYERS = "";
    JMenuItem BoxPlotMenu;

    @Override
    public void init(PluginDescriptor pd, PluginServices ps, GeneralServices gs) {
        super.init(pd, ps, gs);
        assembleWatchedPlayerSet();
        controls = new Controls();
        generalServices.getCallbackApi().addNewReplayListener(nrl);
        BoxPlotMenu = new JMenuItem("Box Plot Menu");
        generalServices.getCallbackApi().addMenuItemToPluginsMenu(BoxPlotMenu);
        BoxPlotMenu.addActionListener(importArchiveActionListener);
    }

    public void destroy() {
        runner = null;
        generalServices.getCallbackApi().removeNewReplayListener(nrl);
        generalServices.getCallbackApi().removeMenuItemFromPluginsMenu(BoxPlotMenu);
    }

    public boolean isActionRequired() {
        return isStringSettingMissing(KEY_WATCHED_PLAYERS);
    }

    private boolean isStringSettingMissing(final String key) {
        final String value = pluginServices.getSettingsApi().getString(key);
        return value == null || value.length() == 0;
    }

    public SettingsControl getSettingsControl() {
        return controls;
    }

    private void assembleWatchedPlayerSet() {
        watchedPlayerSet.clear();

        final String watchedPlayersString = pluginServices.getSettingsApi().getString(KEY_WATCHED_PLAYERS);
        if (watchedPlayersString == null) {
            return; // No players have been added to watch
        }
        for (String watchedPlayer : watchedPlayersString.split(",")) {
            watchedPlayer = watchedPlayer.trim();
            if (watchedPlayer.length() > 0) {
                watchedPlayerSet.add(watchedPlayer);
            }
        }
    }

    class Controls extends BaseSettingsControl {

        private final SettingsApi settings = pluginServices.getSettingsApi();
        private final LanguageApi language = generalServices.getLanguageApi();
        private final JTextField watchedPlayersTextField = new JTextField(settings.getString(KEY_WATCHED_PLAYERS));
        private final JButton importArchiveButton = new JButton("Import Archive");        

        public Container getEditorPanel() {
            final JPanel panel = new JPanel(new BorderLayout());
            final Box box = Box.createVerticalBox();
            Box row = Box.createHorizontalBox();
            row.add(new JLabel(language.getText("tsovplugin.watchedPlayerList")));
            watchedPlayersTextField.setToolTipText(language.getText("tsovplugin.watchedPlayerListToolTip"));
            row.add(watchedPlayersTextField);
            row.add(new JLabel());
            row.add(new JLabel());
            box.add(row);

            generalServices.getGuiUtilsApi().alignBox(box, 4);

            row = Box.createHorizontalBox();
            importArchiveButton.addActionListener(importArchiveActionListener);
            row.add(importArchiveButton);
            box.add(row);

            panel.add(box, BorderLayout.CENTER);

            return panel;
        }

        public void onOkButtonPressed() {
            settings.set(KEY_WATCHED_PLAYERS, watchedPlayersTextField.getText());
            assembleWatchedPlayerSet();
            importArchiveButton.removeActionListener(importArchiveActionListener);
        }

    }

    class ImportArchiveActionListener implements ActionListener {

        public void actionPerformed(ActionEvent e) {
            File outputFile = new File("ApM.data");
            DefaultBoxAndWhiskerCategoryDataset dataset = new DefaultBoxAndWhiskerCategoryDataset();
            List ApMList = new ArrayList();
            List EApMList = new ArrayList();
            List MacroApMList = new ArrayList();
            List RedundancyList = new ArrayList();
            List[][] ApMByTimeList = new ArrayList[6][15];

            for (int CtrX = 0; CtrX < ApMByTimeList.length; CtrX++) {
                for (int CtrY = 0; CtrY < ApMByTimeList[CtrX].length; CtrY++) {
                    ApMByTimeList[CtrX][CtrY] = new ArrayList();
                }
            }

            try {
                FileOutputStream out = new FileOutputStream(outputFile);
                int LastMin = 0;
                try {
                    out.write("ApM,EApM,Redundancy,Macro,Date\n".getBytes());
                } catch (IOException ex) {
                }

                JOptionPane.showMessageDialog(null, "Import Pressed:\n" + generalServices.getInfoApi().getReplayAutoSaveFolder().getPath());
                File files[] = generalServices.getInfoApi().getReplayAutoSaveFolder().listFiles();
                Arrays.sort(files, new Comparator<File>() {

                    public int compare(File f1, File f2) {
                        return Long.valueOf(f1.lastModified()).compareTo(f2.lastModified());
                    }
                });

                int FileCtr = 0;
                for (File file : files) {
                    FileCtr++;
                    int ApMbyTime[] = new int[30];
                    //JOptionPane.showMessageDialog(null, file);
                    IReplay replay = generalServices.getReplayFactoryApi().parseReplay(file.getAbsolutePath(), EnumSet.allOf(ReplayFactoryApi.ReplayContent.class));
                    if (replay.getPlayers().length == 2) {
                        for (int playerCTR = 0; playerCTR < replay.getPlayers().length; playerCTR++) {
                            IPlayer p = replay.getPlayers()[playerCTR];

                            if (watchedPlayerSet.contains(p.getPlayerId().getFullName())) {
                                int ApM = generalServices.getReplayUtilsApi().calculatePlayerApm(replay, p);
                                int EApM = 0; //generalServices.getReplayUtilsApi().calculatePlayerEapm(replay, p);
                                int MacroApM = 0;

                                int Actions = 0;
                                int Redundancy = 0;



                                IGameEvents events = replay.getGameEvents();

                                IAction actions[] = events.getActions();

                                IPlayerSelectionTracker[] selectionTrackers = new IPlayerSelectionTracker[replay.getPlayers().length];
                                for (int i = 0; i < selectionTrackers.length; i++) {
                                    selectionTrackers[i] = generalServices.getReplayUtilsApi().createPlayerSelectionTracker();
                                }

                                for (int ctr = 0; ctr < actions.length; ctr++) {
                                    if (actions[ctr].getActionType() != ActionType.INACTION) {
                                        if (actions[ctr].getPlayer() == (playerCTR)) {
                                            String time = generalServices.getReplayUtilsApi().formatFramesShort(actions[ctr].getFrame(), replay.getGameSpeed());
                                            time = (time.split(":"))[0];

                                            if (generalServices.getEapmUtilsApi().isActionEffective(actions, ctr)) {
                                                EApM++;
                                                try {
                                                    if (actions[ctr].isMacro()) {
                                                        MacroApM++;
                                                        if (Integer.parseInt(time) <= ApMByTimeList[0].length) {
                                                            ApMbyTime[Integer.parseInt(time)]++;
                                                        }
                                                    }
                                                } catch (UnsupportedOperationException ignored) {
                                                    if (actions[ctr] instanceof ISelectAction || actions[ctr] instanceof IHotkeyAction) {
                                                        if (events.isSelectionMacro(selectionTrackers[actions[ctr].getPlayer()].getCurrentSelection())) {
                                                            MacroApM++;
                                                            if (Integer.parseInt(time) <= ApMByTimeList[0].length) {
                                                                ApMbyTime[Integer.parseInt(time)]++;
                                                            }
                                                        }
                                                    }
                                                }
                                            }


                                            if (Integer.parseInt(time) <= ApMByTimeList[0].length) {
                                                //ApMbyTime[Integer.parseInt(time)]++;
                                                LastMin = Integer.parseInt(time);
                                            }
                                            Actions++;

                                        }
                                    }
                                }

                                EApM = (int) ((double) (ApM) * ((double) (EApM - p.getExcludedEffectiveActionsCount()) / (double) (Actions - p.getExcludedActionsCount())));
                                MacroApM = (int) ((double) MacroApM / ((double) p.getActionsCount() / (double) ApM));
                                Redundancy = (int) (100 - ((double) (EApM * 100) / (double) ApM));
                                try {
                                    ApMList.add(new Double(ApM));
                                    EApMList.add(new Double(EApM));
                                    MacroApMList.add(new Double(MacroApM));
                                    RedundancyList.add(new Double(Redundancy));


                                    for (int ctr = 0; ctr < LastMin; ctr++) {
                                        int Group = ((FileCtr - 1) / (files.length / ApMByTimeList.length));
                                        if (Group >= ApMByTimeList.length) {
                                            Group = ApMByTimeList.length - 1;
                                        }
                                        ApMByTimeList[Group][ctr].add(new Double(ApMbyTime[ctr]));
                                    }

                                    out.write((ApM + "," + EApM + "," + Redundancy + "," + MacroApM + "," + replay.getSaveTime() + "\n").getBytes());
                                } catch (IOException ex) {
                                }

                            }
                        }
                    }
                }
            } catch (FileNotFoundException ex) {
            }

            for (int GroupCtr = 0; GroupCtr < ApMByTimeList.length; GroupCtr++) {
                for (int GameCtr = 0; GameCtr < ApMByTimeList[GroupCtr].length; GameCtr++) {
                    List addList = ApMByTimeList[GroupCtr][GameCtr];
                    dataset.add(addList, (GroupCtr + 1), GameCtr + 1);
                }
            }

            CategoryAxis xAxis = new CategoryAxis("Min");
            final NumberAxis yAxis = new NumberAxis("ApM");
            yAxis.setAutoRangeIncludesZero(false);
            final BoxAndWhiskerRenderer renderer = new BoxAndWhiskerRenderer();
            renderer.setFillBox(false);
            renderer.setToolTipGenerator(new BoxAndWhiskerToolTipGenerator());
            final CategoryPlot plot = new CategoryPlot(dataset, xAxis, yAxis, renderer);

            final JFreeChart chart = new JFreeChart(
                    "ApM Box Plot",
                    new Font("SansSerif", Font.BOLD, 14),
                    plot,
                    true);
            final ChartPanel chartPanel = new ChartPanel(chart);
            chartPanel.setPreferredSize(new java.awt.Dimension(450, 270));
            //setContentPane(chartPanel);
            JFrame chartFrame = new JFrame("APM Chart");
            chartFrame.setContentPane(chartPanel);
            chartFrame.pack();
            RefineryUtilities.centerFrameOnScreen(chartFrame);
            chartFrame.setVisible(true);
        }
    }

    class NRL implements NewReplayListener {

        public void newReplayDetected(File file) {
            replayFile = file;
            runner = new Thread(new ParceReplay(file));
            runner.start();
        }
    }

    class ParceReplay implements Runnable {

        File replayFile;

        ParceReplay(File replayFile) {
            this.replayFile = replayFile;
        }

        public void run() {
            IReplay replay = generalServices.getReplayFactoryApi().parseReplay(replayFile.getAbsolutePath(), EnumSet.allOf(ReplayFactoryApi.ReplayContent.class));

            for (int playerCTR = 0; playerCTR < replay.getPlayers().length; playerCTR++) {
                IPlayer p = replay.getPlayers()[playerCTR];

                if (!watchedPlayerSet.contains(p.getPlayerId().getFullName())) {
                    int ApM = generalServices.getReplayUtilsApi().calculatePlayerApm(replay, p);
                    int EApM = generalServices.getReplayUtilsApi().calculatePlayerEapm(replay, p);
                    int Actions = 0;
                    int Redundancy = 0;

                    IGameEvents events = replay.getGameEvents();
                    IAction actions[] = events.getActions();

                    for (int ctr = 0; ctr < actions.length; ctr++) {
                        if (actions[ctr].getActionType() != ActionType.INACTION) {
                            if (actions[ctr].getPlayer() == (playerCTR)) {
                                if (generalServices.getEapmUtilsApi().isActionEffective(actions, ctr)) {
                                    //EApM++;
                                }
                                Actions++;
                            }
                        }
                    }

                    //EApM = (int) ((double) (ApM) * ((double) (EApM - p.getExcludedEffectiveActionsCount()) / (double) (Actions - p.getExcludedActionsCount())));
                    Redundancy = (int) (100 - ((double) (EApM * 100) / (double) ApM));

                    StringBuilder sb = new StringBuilder();
                    sb.append(p.getPlayerId().getFullName()).append("\n");
                    sb.append(p.getPlayerId().getBattleNetProfileUrl(BnetLanguage.ENGLISH)).append("\n");
                    sb.append(p.getRace()).append("\n");


                    sb.append("EApM: ").append(EApM).append("\n");
                    sb.append("ApM: ").append(ApM).append("\n");
                    sb.append("Redundancy: ").append(Redundancy).append("\n");

                    sb.append("PlayerCTR: ").append(playerCTR).append("\n" + "Counted Actions: ").append(Actions).append("\n");
                    sb.append("Players P Actions:").append(p.getActionsCount()).append("\n");
                    sb.append(Actions - p.getExcludedActionsCount());

                    JOptionPane.showMessageDialog(null, sb.toString());
                    generalServices.getProfileApi().queryProfile(p.getPlayerId(), enemyProfileListener, false, false);
                }
            }
        }
    }

    class EnemyProfileListener implements ProfileListener {

        public void profileReady(IProfile ip, boolean bln) {
            if (ip != null) {
                JOptionPane.showMessageDialog(null, "League: " + ip.getBestRanks()[0].getLeague());
            }
        }
    }
}
